#include "TTToeBoard.h"
#include <cstdio>
#include <list>
#include <random>
#include <iostream>

namespace SmartTTToe {
	TTToeBoard::TTToeBoard(int size) : 
boardMap(NULL),
evalBoard(NULL),
TScore(NULL),
KScore(NULL)
{
	this->boardSize = size;
	this->stepCount = 0;

	// Initialize TScore and KScore
	this->TScore = new int[5];
	this->TScore[0] = 0;
	this->TScore[1] = 1;
	this->TScore[2] = 9;
	this->TScore[3] = 85;
	this->TScore[4] = 769;
	this->KScore = new int[5];
	this->KScore[0] = 0;
	this->KScore[1] = 4;
	this->KScore[2] = 28;
	this->KScore[3] = 256;
	this->KScore[4] = 2308;

	// Initialize board map
	this->boardMap = new char*[size];
	for (int i = 0; i < size; i ++) {
		this->boardMap[i] = new char[size];
	}
	for (int i = 0; i < size; i ++) {
		for (int j = 0; j < size; j ++) {
			this->boardMap[i][j] = ' ';
		}
	}

	// Initialize the evalBoard
	this->evalBoard = new int*[size];
	for (int i = 0; i < size; i ++) {
		this->evalBoard[i] = new int[size];
	}
	for (int i = 0; i < size; i ++) {
		for (int j = 0; j < size; j ++) {
			this->evalBoard[i][j] = 0;
		}
	}
}

TTToeBoard::~TTToeBoard(void) {
	// Free the TScore and KScore
	if (this->TScore) {
		delete [] this->TScore;
		this->TScore = NULL;
	}
	if (this->KScore) {
		delete [] this->KScore;
		this->KScore = NULL;
	}

	// Free the board map
	if (this->boardMap) {
		for (int i = 0; i < this->boardSize; i ++) {
			delete [] this->boardMap[i];
		}
		delete [] this->boardMap;
		this->boardMap = NULL;
	}	

	// Free the evaluation board
	if (this->evalBoard) {
		for (int i = 0; i < this->boardSize; i ++) {
			delete [] this->evalBoard[i];
		}
		delete [] this->evalBoard;
		this->evalBoard = NULL;
	}
}

int TTToeBoard::insert(int x, int y, bool turn) {
	if (x >= this->boardSize ||
		y >= this->boardSize ||
		x < 0 ||
		y < 0) {
			// Error insertion
			return -1;
	} else {
		this->stepCount ++;
		if (turn) {
			this->boardMap[x][y] = PLAYER_2_;
		} else {
			this->boardMap[x][y] = PLAYER_1_;
		}
	}
}

// ******************************************************
// Private function
// ******************************************************
void TTToeBoard::evaluateBoard(char** cells, char player) {

	// Initialize the evaluation board
	for (int i = 0; i < this->boardSize; i ++) {
		for (int j = 0; j < this->boardSize; j ++) {
			this->evalBoard[i][j] = 0;
		}
	}

	for (int i; i < this->boardSize; i ++) {
		for (int j = 0; j < this->boardSize; j ++) {
			if (this->boardMap[i][j] != ' ') {
				this->evalBoard[i][j] = -1;
			}
		}
	}

	int player1Counter;
	int player2Counter;

	// Checking row
	for (int row = 0; row < this->boardSize; row ++) {
		for (int col = 0; col < this->boardSize - 4; col ++) {
			player1Counter = 0;
			player2Counter = 0;
			for (int i = 0; i < 5; i ++) {
				if (cells[row][col + i] == PLAYER_1_) {
					player1Counter ++;
				}
				if (cells[row][col + i] == PLAYER_2_) {
					player2Counter ++;
				}
			}

			if ((player1Counter * player2Counter == 0) && (player1Counter != player2Counter)) {
				for (int i = 0; i < 5; i ++) {
					if (cells[row][col + i] == ' ') {
						if (player == PLAYER_1_) {
							this->evalBoard[row][col + i] += this->TScore[player1Counter];
						} else {
							this->evalBoard[row][col + i] += this->KScore[player1Counter];
						}

						if (player == PLAYER_2_) {
							this->evalBoard[row][col + i] += this->TScore[player2Counter];
						} else {
							this->evalBoard[row][col + i] += this->KScore[player2Counter];
						}	

						if (player1Counter == 4 || player2Counter == 4) {
							this->evalBoard[row][col + i] <<= 1;
						}
					}
				}
			}
		}
	}	// End checking row



	// Check column
	for (int row = 0; row < this->boardSize - 4; row ++) {
		for (int col = 0; col < this->boardSize; col ++) {
			player1Counter = 0;
			player2Counter = 0;
			for (int i = 0; i < 5; i ++) {
				if (this->boardMap[row + i][col] == PLAYER_1_) {
					player1Counter ++;
				}
				if (this->boardMap[row + i][col] == PLAYER_2_) {
					player2Counter ++;
				}
			}

			if (player1Counter * player2Counter == 0 && player1Counter != player2Counter) {
				for (int i = 0; i < 5; i ++) {
					if (cells[row + i][col] == ' ') {
						if (player == PLAYER_1_) {
							this->evalBoard[row + i][col] += this->TScore[player2Counter];
						} else {
							this->evalBoard[row + i][col] += this->KScore[player2Counter];
						}
						if (player == PLAYER_2_) {
							this->evalBoard[row + i][col] += this->TScore[player1Counter];
						} else {
							this->evalBoard[row + i][col] += this->KScore[player1Counter];
						}
						if (player1Counter == 4 || player2Counter == 4) {
							this->evalBoard[row + i][col] <<=  1;
						} 
					}
				}
			}
		}
	}	// End checking column

	// Duong cheo xuong
	for (int row = 0; row < this->boardSize - 4; row++) {
		for (int col = 0; col < this->boardSize - 4; col ++) {
			player1Counter = 0;
			player2Counter = 0;
			for (int i = 0; i < 5; i++) {
				if (cells[row + i][col + i] == PLAYER_1_) player1Counter++;
				if (cells[row + i][col + i] == PLAYER_2_) player2Counter++;
			}

			if (player1Counter * player2Counter == 0 && player1Counter != player2Counter) {
				for (int i = 0; i < 5; i++){
					if (cells[row + i][col + i] == ' ')	{
						if (player == PLAYER_1_) {
							this->evalBoard[row + i, col + i] += TScore[player2Counter];
						} else {
							this->evalBoard[row + i, col + i] += KScore[player2Counter];
						}
						if (player == PLAYER_2_) {
							this->evalBoard[row + i][col + i] += TScore[player1Counter];
						} else {
							this->evalBoard[row + i, col + i] += KScore[player1Counter];
						}						
						if (player1Counter == 4 || player2Counter == 4) {
							this->evalBoard[row + i][col + i] <<= 1;
						}
					}
				}
			}
		}
	}	// End checking duong cheo xuong

	//Duong cheo len
	for (int row = 4; row < this->boardSize; row++) {
		for (int col = 0; col < this->boardSize - 4; col++)
		{
			player1Counter = 0;
			player2Counter = 0;
			for (int i = 0; i < 5; i++)
			{
				if (cells[row - i][col + i] == PLAYER_2_) player2Counter++;
				if (cells[row - i][col + i] == PLAYER_1_) player1Counter++;
			}

			if (player2Counter * player1Counter == 0 && player2Counter != player1Counter) {
				for (int i = 0; i < 5; i++) {
					if (cells[row - i][col + i] == ' ')	{
						if (player == PLAYER_2_) {
							this->evalBoard[row - i][col + i] += this->TScore[player1Counter];
						} else {
							this->evalBoard[row - i][col + i] += this->KScore[player1Counter];
						}
						if (player == PLAYER_1_) {
							this->evalBoard[row - i][col + i] += this->TScore[player2Counter];
						} else {
							this->evalBoard[row - i][col + i] += this->KScore[player2Counter];
						}
						if (player1Counter == 4 || player2Counter == 4)
							this->evalBoard[row - i][col + i] <<= 1;
					}
				}
			}
		}
	}	// End checking duong cheo len
}


TTToeState* TTToeBoard::GetMaxNode() {
	TTToePosition* p = new TTToePosition(0, 0);
	std::list<TTToeState*> stateList;
	int t = INT_MIN;
	for (int i = 0; i < this->boardSize; i ++) {
		for (int j = 0; j < this->boardSize; j ++) {
			if (t < this->evalBoard[i][j]) {
				t = this->evalBoard[i][j];
				p->SetX(i);
				p->SetY(j);
				stateList.clear();	// TODO: make sure to avoid memory leak here
				stateList.push_back(new TTToeState(p, t));
			} else if (t == this->evalBoard[i][j]){
				p->SetX(i);
				p->SetY(j);
				stateList.push_back(new TTToeState(p, t));
			}
		}
	}

	/*for (std::list<TTToeState*>::iterator it = stateList.begin(); it != stateList.end(); it ++) {
		TTToeState* currentState = (*it);
		this->evalBoard[currentState->GetPosition()->GetX()][currentState->GetPosition()->GetY()] = 0;
	}*/
	/*std::*/
	// TODO (Minh Luan): continue this
	return NULL;	// TODO: replace this
}

int TTToeBoard::randomFrom(const int min, const int max) {
	// TODO (Minh Luan): implement this
	return 0;
}

}	// namespace SmartTTToe
